/*
 * Copyright (c) 2022-2023 Termony Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "los_interrupt.h"
#include "los_context.h"
#include "los_debug.h"
#include "los_hook.h"
#include "los_task.h"
#include "los_sched.h"
#include "los_memory.h"
#include "los_membox.h"
#if (LOSCFG_CPUP_INCLUDE_IRQ == 1)
#include "los_cpup.h"
#endif

#include "securec.h"
#include "los_arch_cpu.h"
#include "los_arch_gic.h"
#include "los_arch_interrupt.h"

#ifdef __GNUC__
LITE_OS_SEC_VEC
#endif

/* 异常寄存器结构. */
EXC_CONTEXT_S g_exc = {0};
/* 异常信息控制块. */
ExcInfo g_excInfo = {0};
/* 中断嵌套计数器. */
volatile UINTPTR g_intCount = 0;
/* 中断控制块. */
static struct {
    struct {
        HWI_PROC_FUNC fn;
        VOID *parm;
    } handler[OS_HWI_MAX_NUM];
    UINT32 curHwiNum;
#if (LOSCFG_DEBUG_TOOLS == 1)
    CHAR *name[OS_HWI_MAX_NUM];
    UINT32 triggerCnt[OS_HWI_MAX_NUM];
#endif
} g_hwiCb;


UINT32 ArchIntLock(VOID)
{
    UINT32 intSave;

    __asm__ __volatile__("MRS %0, DAIF\n"
                         "MSR DAIFSET, #2\n"
                         "DSB SY\n"
                         "ISB SY\n"
                         : "=r"(intSave) :: "memory");
    return intSave;
}

VOID ArchIntRestore(UINT32 intSave)
{
    __asm__ __volatile__("MSR DAIF, %0" :: "r"(intSave));
}

UINT32 ArchIntUnLock(VOID)
{
    UINT32 intSave;

    __asm__ __volatile__("MSR DAIFCLR, #2\n"
                         "DSB SY\n"
                         "ISB SY\n"
                         "MRS %0, DAIF\n"
                         : "=r"(intSave) :: "memory");
    return intSave;
}

/* 设置目标CPU. */
STATIC UINT32 HwiSetTargetCPU(HWI_HANDLE_T hwiNum, UINT32 cpuId)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicIrqSetTargetCpu(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum, (1UL << cpuId));
    return LOS_OK;
}

/* 设置中断优先级. */
STATIC UINT32 HwiSetPriority(HWI_HANDLE_T hwiNum, UINT8 priority)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (priority > OS_HWI_PRIO_LOWEST) {
        return OS_ERRNO_HWI_PRIO_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicSetIrqPriority(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum, priority);
    return LOS_OK;
}

/* 中断使能. */
STATIC UINT32 HwiUnmask(HWI_HANDLE_T hwiNum)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicIrqUmask(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum);
    return LOS_OK;
}

/* 中断禁止. */
STATIC UINT32 HwiMask(HWI_HANDLE_T hwiNum)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicIrqMask(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum);
    return LOS_OK;
}

/* 中断挂起. */
STATIC UINT32 HwiPending(HWI_HANDLE_T hwiNum)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicSetPendingIrq(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum);
    return LOS_OK;
}

/* 中断清除. */
STATIC UINT32 HwiClear(HWI_HANDLE_T hwiNum)
{
    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HalGicClearPendingIrq(LOSCFG_PLATFORM_GIC_SEQUENCE, hwiNum);
    return LOS_OK;
}

/* 获取中断号. */
STATIC UINT32 HwiNumGet(VOID)
{
    return g_hwiCb.curHwiNum;
}

HwiControllerOps g_archHwiOps = {
    .enableIrq      = HwiUnmask,
    .disableIrq     = HwiMask,
    .setIrqPriority = HwiSetPriority,
    .getCurIrqNum   = HwiNumGet,
    .triggerIrq     = HwiPending,
    .clearIrq       = HwiClear,
};


/* 注册中断处理函数. */
#if (LOSCFG_PLATFORM_HWI_WITH_ARG == 1)
VOID OsSetVector(UINTPTR num, HWI_PROC_FUNC vector, VOID *arg)
{
    if (num < OS_HWI_MAX_NUM) {
        g_hwiCb.handler[num].fn = vector;
        g_hwiCb.handler[num].parm = arg;
    }
}
#else
VOID OsSetVector(UINTPTR num, HWI_PROC_FUNC vector)
{
    if (num < OS_HWI_MAX_NUM) {
        g_hwiCb.handler[num].fn = vector;
        g_hwiCb.handler[num].parm = NULL;
    }
}
#endif

/* 默认中断处理函数. */
#if (LOSCFG_PLATFORM_HWI_WITH_ARG == 1)
LITE_OS_SEC_TEXT_MINOR VOID HalHwiDefaultHandler(VOID *parm)
{
    UINT32 hwiNum = HwiNumGet();

    (VOID)parm;

    if (hwiNum >= OS_HWI_MAX_NUM) {
        return;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return;
    }

    PRINT_ERR("%s() The interrupt handler was not registered, intId = %u\n", __FUNCTION__, hwiNum);
}
#else
LITE_OS_SEC_TEXT_MINOR VOID HalHwiDefaultHandler(VOID)
{
    UINT32 hwiNum = HwiNumGet();

    (VOID)parm;

    if (hwiNum >= OS_HWI_MAX_NUM) {
        return;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return;
    }

    PRINT_ERR("%s() The interrupt handler was not registered, intId = %u\n", __FUNCTION__, hwiNum);
}
#endif

/* 异常管理初始化. */
LITE_OS_SEC_TEXT_INIT VOID HalHwiInit(VOID)
{
    HalGicInit(LOSCFG_PLATFORM_GIC_SEQUENCE, 0);
    memset_s(&g_hwiCb, sizeof(g_hwiCb), 0, sizeof(g_hwiCb));
    for (UINT32 index = 0; index < OS_HWI_MAX_NUM; index++) {
        g_hwiCb.handler[index].fn = HalHwiDefaultHandler;
    }
}

/* 创建中断. */
LITE_OS_SEC_TEXT_INIT UINT32 ArchHwiCreate(HWI_HANDLE_T hwiNum,
                                           HWI_PRIOR_T hwiPrio,
                                           HWI_MODE_T hwiMode,
                                           HWI_PROC_FUNC hwiHandler,
                                           HwiIrqParam *irqParam)
{
    (VOID)hwiMode;

    if (hwiHandler == NULL) {
        return OS_ERRNO_HWI_PROC_FUNC_NULL;
    }

    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiPrio > OS_HWI_PRIO_LOWEST) {
        return OS_ERRNO_HWI_PRIO_INVALID;
    }

    HalGicInit(LOSCFG_PLATFORM_GIC_SEQUENCE, 0);
    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (g_hwiCb.handler[hwiNum].fn != HalHwiDefaultHandler) {
        return OS_ERRNO_HWI_ALREADY_CREATED;
    }

    UINTPTR intSave = LOS_IntLock();
#if (LOSCFG_PLATFORM_HWI_WITH_ARG == 1)
    if ((irqParam != NULL) && (irqParam->pDevId != NULL)) {
        OsSetVector(hwiNum, hwiHandler, irqParam->pDevId);
    } else {
        OsSetVector(hwiNum, hwiHandler, NULL);
    }
#else
    (VOID)irqParam;
    OsSetVector(hwiNum, hwiHandler);
#endif

#if (LOSCFG_DEBUG_TOOLS == 1)
    if ((irqParam != NULL) && (irqParam->pName != NULL)) {
        g_hwiCb.name[hwiNum] = (CHAR *)irqParam->pName;
    }
    g_hwiCb.triggerCnt[hwiNum] = 0;
#endif

    HwiSetTargetCPU(hwiNum, HalGetCpuId());
    HwiSetPriority(hwiNum, hwiPrio);
    HwiUnmask(hwiNum);

    LOS_IntRestore(intSave);

    return LOS_OK;
}

/* 删除中断. */
LITE_OS_SEC_TEXT_INIT UINT32 ArchHwiDelete(HWI_HANDLE_T hwiNum, HwiIrqParam *irqParam)
{
    (VOID)irqParam;

    if (hwiNum >= OS_HWI_MAX_NUM) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    if (hwiNum >= (HWI_HANDLE_T) HalGicGetMaxIrqNum()) {
        return OS_ERRNO_HWI_NUM_INVALID;
    }

    HwiMask(hwiNum);

    UINTPTR intSave = LOS_IntLock();
    g_hwiCb.handler[hwiNum].fn = HalHwiDefaultHandler;
    g_hwiCb.handler[hwiNum].parm = NULL;
    LOS_IntRestore(intSave);

    return LOS_OK;
}

WEAK VOID HalPreInterruptHandler(UINT32 arg)
{
    (VOID)arg;
    return;
}

WEAK VOID HalAftInterruptHandler(UINT32 arg)
{
    (VOID)arg;
    return;
}

/* 异常处理统一入口. */
LITE_OS_SEC_TEXT VOID HalInterrupt(UINTPTR hwiIndex)
{
    UINTPTR intSave;

    intSave = LOS_IntLock();
    g_intCount++;
    LOS_IntRestore(intSave);

    if (hwiIndex >= OS_HWI_MAX_NUM) {
        PRINTK("Interrupt %u is triggered.\n", (UINT32) hwiIndex);
        goto EXIT;
    }

    g_hwiCb.curHwiNum = (UINT32) hwiIndex;
    OsHookCall(LOS_HOOK_TYPE_ISR_ENTER, hwiIndex);

#if (LOSCFG_CPUP_INCLUDE_IRQ == 1)
    OsCpupIrqStart(hwiIndex);
#endif

    HalPreInterruptHandler(hwiIndex);

    if (g_hwiCb.handler[hwiIndex].fn != 0) {
#if (LOSCFG_PLATFORM_HWI_WITH_ARG == 1)
        g_hwiCb.handler[hwiIndex].fn((VOID *)g_hwiCb.handler[hwiIndex].parm);
#else
        g_hwiCb.handler[hwiIndex].fn();
#endif
    }

#if (LOSCFG_DEBUG_TOOLS == 1)
    ++g_hwiCb.triggerCnt[hwiIndex];
#endif

    HalAftInterruptHandler(hwiIndex);

#if (LOSCFG_CPUP_INCLUDE_IRQ == 1)
    OsCpupIrqEnd(hwiIndex);
#endif

    OsHookCall(LOS_HOOK_TYPE_ISR_EXIT, hwiIndex);
    g_hwiCb.curHwiNum = 0;

EXIT:
    intSave = LOS_IntLock();
    g_intCount--;
    LOS_IntRestore(intSave);
}

/* 判断是否正在中断处理中. */
UINT32 ArchIsIntActive(VOID)
{
    return (g_intCount > 0);
}

#if (LOSCFG_DEBUG_TOOLS == 1)
/* 判断中断是否被创建. */
BOOL OsGetHwiCreated(UINT32 index)
{
    if (g_hwiCb.handler[index].fn != HalHwiDefaultHandler) {
        return TRUE;
    }

    return FALSE;
}

/* 获取中断名称. */
CHAR *OsGetHwiFormName(UINT32 index)
{
    return g_hwiCb.name[index];
}

/* 获取中断触发次数. */
UINT32 OsGetHwiFormCnt(UINT32 index)
{
    return g_hwiCb.triggerCnt[index];
}
#endif


#if (LOSCFG_KERNEL_PRINTF != 0)
STATIC VOID OsExceptionCause(UINT8 ec, UINTPTR faultAddr)
{
    switch (ec) {
        case 0x00: /* 未知原因. */
            PRINTK("Unknown reason.\n");
            break;
        case 0x01: /* 被捕获的WFI或WFE指令执行. */
            PRINTK("Trapped WFI or WFE instruction execution.\n");
            break;
        case 0x03: /* AARCH32: 被捕获的MCR或MRC访问(CP15). */
            PRINTK("Trapped MCR or MRC access with (CP15).\n");
            break;
        case 0x04: /* AARCH32: 被捕获的MCRR或MRRC访问(CP15). */
            PRINTK("Trapped MCRR or MRRC access with (CP15).\n");
            break;
        case 0x05: /* AARCH32: 被捕获的MCR或MRC访问(CP14). */
            PRINTK("Trapped MCR or MRC access with (CP14).\n");
            break;
        case 0x06: /* AARCH32: 被捕获的LDC或STC访问. */
            PRINTK("Trapped LDC or STC access.\n");
            break;
        case 0x07: /* 被捕获的对SVE, 高级SIMD或浮点功能的访问. */
            PRINTK("Trapped access to SVE, Advanced SIMD, or floating-point functionality.\n");
            break;
        case 0x08: /* 从ID组捕获的VMRS访问. */
            PRINTK("Trapped VMRS access from ID group trap.\n");
            break;
        case 0x09: /* 由于HCR_EL2.API == 0或SCR_EL3.API == 0导致的被捕获的指针认证指令执行. */
            PRINTK("Trapped use of a Pointer authentication instruction because HCR_EL2.API == 0 || SCR_EL3.API == 0.\n");
            break;
        case 0x0a: /* 被捕获的LD64B或ST64B*指令执行. */
            PRINTK("Trapped execution of an LD64B or ST64B* instruction.\n");
            break;
        case 0x0c: /* AARCH32: 被捕获的MRRC访问(coproc == 0b1110). */
            PRINTK("Trapped MRRC access with (coproc==0b1110).\n");
            break;
        case 0x0d: /* 分支目标异常. */
            PRINTK("Branch Target Exception.\n");
            break;
        case 0x0e: /* 执行状态非法. */
            PRINTK("Illegal Execution state.\n");
            break;
        case 0x11: /* AARCH32: 在AARCH32状态下执行SVC指令. */
            PRINTK("SVC instruction execution in AArch32 state.\n");
            break;
        case 0x12: /* AARCH32: 当HVC未被禁用时, 在AARCH32状态下执行HVC指令. */
            PRINTK("HVC instruction execution in AArch32 state, when HVC is not disabled.\n");
            break;
        case 0x13: /* AARCH32: 当SMC没有被禁用时, 在AARCH32状态下执行SMC指令. */
            PRINTK("SMC instruction execution in AArch32 state, when SMC is not disabled.\n");
            break;
        case 0x15: /* AARCH64: 在AARCH64状态下执行SVC指令. */
            PRINTK("SVC instruction execution in AArch64 state.\n");
            break;
        case 0x16: /* AARCH64: 当HVC未被禁用时, 在AARCH64状态下执行HVC指令. */
            PRINTK("HVC instruction execution in AArch64 state, when HVC is not disabled.\n");
            break;
        case 0x17: /* AARCH64: 当SMC没有被禁用时, 在AARCH64状态下执行SMC指令. */
            PRINTK("SMC instruction execution in AArch64 state, when SMC is not disabled.\n");
            break;
        case 0x18: /* AARCH64: 在AARCH64状态执行MSR、MRS或系统指令异常, 未使用EC 0x00, 0x01或0x07报告. */
            PRINTK("Trapped MSR, MRS or System instruction execution in AArch64 state.\n");
            break;
        case 0x19: /* 被捕获的对SVE功能的访问. */
            PRINTK("Trapped access to SVE functionality.\n");
            break;
        case 0x1a: /* 被捕获的ERET、ERETAA或ERETAB指令执行. */
            PRINTK("Trapped ERET, ERETAA, or ERETAB instruction execution.\n");
            break;
        case 0x1c: /* 指针认证指令认证失败异常. */
            PRINTK("Exception from a Pointer Authentication instruction authentication failure.\n");
            break;
        case 0x1f: /* EL3的实现定义异常. */
            PRINTK("IMPLEMENTATION DEFINED exception to EL3.\n");
            break;
        case 0x20: /* AARCH32/AARCH64: 来自较低异常级别的指令中止异常. */
            PRINTK("Instruction Abort from a lower Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x21: /* 在异常级别没有改变的情况下的指令中止异常. */
            PRINTK("Instruction Abort taken without a change in Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x22: /* PC对齐异常. */
            PRINTK("PC alignment fault @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x24: /* AARCH32/AARCH64: 来自较低异常级别的数据中止异常. */
            PRINTK("Data Abort from a lower Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x25: /* 在异常级别没有改变的情况下的数据中止异常. */
            PRINTK("Data Abort taken without a change in Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x26: /* SP对齐异常. */
            PRINTK("SP alignment fault exception.\n");
            break;
        case 0x27: /* 内存操作异常. */
            PRINTK("Memory Operation Exception.\n");
            break;
        case 0x28: /* AARCH32: 在AARCH32状态下捕获的浮点异常. */
            PRINTK("Trapped floating-point exception taken from AArch32 state.\n");
            break;
        case 0x2c: /* AARCH64: 在AARCH64状态下捕获的浮点异常. */
            PRINTK("Trapped floating-point exception taken from AArch64 state.\n");
            break;
        case 0x2f: /* 系统错误中断. */
            PRINTK("SError interrupt.\n");
            break;
        case 0x30: /* AARCH32/AARCH64: 来自较低异常级别的断点异常. */
            PRINTK("Breakpoint exception from a lower Exception level.\n");
            break;
        case 0x31: /* 在没有改变异常级别的情况下发生的断点异常. */
            PRINTK("Breakpoint exception taken without a change in Exception level.\n");
            break;
        case 0x32: /* AARCH32/AARCH64: 来自较低异常级别的软件步骤异常. */
            PRINTK("Software Step exception from a lower Exception level.\n");
            break;
        case 0x33: /* 在没有改变异常级别的情况下发生的软件步骤异常. */
            PRINTK("Software Step exception taken without a change in Exception level.\n");
            break;
        case 0x34: /* AARCH32/AARCH64: 来自较低异常级别的观察点异常. */
            PRINTK("Watchpoint exception from a lower Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x35: /* 在没有更改异常级别的情况下发生的观察点异常. */
            PRINTK("Watchpoint exception taken without a change in Exception level @ 0x%016" PRIxPTR "\n", faultAddr);
            break;
        case 0x38: /* AARCH32: 在AARCH32状态下执行BKPT指令. */
            PRINTK("BKPT instruction execution in AArch32 state.\n");
            break;
        case 0x3a: /* AARCH32: 在AARCH32状态下捕获到的向量表异常. */
            PRINTK("Vector Catch exception from AArch32 state.\n");
            break;
        case 0x3c: /* AARCH64: 在AARCH64状态下执行BRK指令. */
            PRINTK("BRK instruction execution in AArch64 state.\n");
            break;
        default:
            PRINTK("Error (%u) is unknow.\n", ec);
            break;
    }
}

STATIC VOID OsExcTypeInfo(const ExcInfo *excInfo)
{
    const char *phaseStr[] = {"exc in init", "exc in task", "exc in hwi"};
    UINT8 ec = (UINT8) excInfo->type;

    OsExceptionCause(ec, excInfo->faultAddr);
    PRINTK("Type      = %u\n", excInfo->type);
    PRINTK("ThrdPid   = %u\n", excInfo->thrdPid);
    PRINTK("Phase     = %s\n", phaseStr[excInfo->phase]);
    PRINTK("FaultAddr = 0x%016" PRIxPTR "\n", excInfo->faultAddr);
}

STATIC VOID OsExcCurTaskInfo(const ExcInfo *excInfo)
{
    if (excInfo->phase == OS_EXC_IN_TASK) {
        PRINTK("Current task info:\n");
        LosTaskCB *taskCB = OS_TCB_FROM_TID(LOS_CurTaskIDGet());
        PRINTK("Task name = %s\n", taskCB->taskName);
        PRINTK("Task ID   = %u\n", taskCB->taskID);
        PRINTK("Task SP   = %p\n", taskCB->stackPointer);
        PRINTK("Task ST   = 0x%016" PRIxPTR "\n", taskCB->topOfStack);
        PRINTK("Task SS   = 0x%x\n", taskCB->stackSize);
    } else if (excInfo->phase == OS_EXC_IN_HWI) {
        PRINTK("Exception occur in interrupt phase!\n");
    } else {
        PRINTK("Exception occur in system init phase!\n");
    }
}

STATIC VOID OsExcRegInfo(const ExcInfo *excInfo)
{
    PRINTK("Exception reg dump:\n");
    PRINTK("SPSR = 0x%016" PRIxPTR "\n", excInfo->context->spsr);
    PRINTK("ELR  = 0x%016" PRIxPTR "\n", excInfo->context->elr);
    PRINTK("SP   = 0x%016" PRIxPTR "\n", excInfo->context->sp);
    PRINTK("X0   = 0x%016" PRIxPTR "\n", excInfo->context->x0);
    PRINTK("X1   = 0x%016" PRIxPTR "\n", excInfo->context->x1);
    PRINTK("X2   = 0x%016" PRIxPTR "\n", excInfo->context->x2);
    PRINTK("X3   = 0x%016" PRIxPTR "\n", excInfo->context->x3);
    PRINTK("X4   = 0x%016" PRIxPTR "\n", excInfo->context->x4);
    PRINTK("X5   = 0x%016" PRIxPTR "\n", excInfo->context->x5);
    PRINTK("X6   = 0x%016" PRIxPTR "\n", excInfo->context->x6);
    PRINTK("X7   = 0x%016" PRIxPTR "\n", excInfo->context->x7);
    PRINTK("X8   = 0x%016" PRIxPTR "\n", excInfo->context->x8);
    PRINTK("X9   = 0x%016" PRIxPTR "\n", excInfo->context->x9);
    PRINTK("X10  = 0x%016" PRIxPTR "\n", excInfo->context->x10);
    PRINTK("X11  = 0x%016" PRIxPTR "\n", excInfo->context->x11);
    PRINTK("X12  = 0x%016" PRIxPTR "\n", excInfo->context->x12);
    PRINTK("X13  = 0x%016" PRIxPTR "\n", excInfo->context->x13);
    PRINTK("X14  = 0x%016" PRIxPTR "\n", excInfo->context->x14);
    PRINTK("X15  = 0x%016" PRIxPTR "\n", excInfo->context->x15);
    PRINTK("X16  = 0x%016" PRIxPTR "\n", excInfo->context->x16);
    PRINTK("X17  = 0x%016" PRIxPTR "\n", excInfo->context->x17);
    PRINTK("X18  = 0x%016" PRIxPTR "\n", excInfo->context->x18);
    PRINTK("X19  = 0x%016" PRIxPTR "\n", excInfo->context->x19);
    PRINTK("X20  = 0x%016" PRIxPTR "\n", excInfo->context->x20);
    PRINTK("X21  = 0x%016" PRIxPTR "\n", excInfo->context->x21);
    PRINTK("X22  = 0x%016" PRIxPTR "\n", excInfo->context->x22);
    PRINTK("X23  = 0x%016" PRIxPTR "\n", excInfo->context->x23);
    PRINTK("X24  = 0x%016" PRIxPTR "\n", excInfo->context->x24);
    PRINTK("X25  = 0x%016" PRIxPTR "\n", excInfo->context->x25);
    PRINTK("X26  = 0x%016" PRIxPTR "\n", excInfo->context->x26);
    PRINTK("X27  = 0x%016" PRIxPTR "\n", excInfo->context->x27);
    PRINTK("X28  = 0x%016" PRIxPTR "\n", excInfo->context->x28);
    PRINTK("X29  = 0x%016" PRIxPTR "\n", excInfo->context->x29);
    PRINTK("X30  = 0x%016" PRIxPTR "\n", excInfo->context->x30);
}

#if (LOSCFG_KERNEL_BACKTRACE == 1)
STATIC VOID OsExcBackTraceInfo(const ExcInfo *excInfo)
{
    CHAR buffer[LOSCFG_BACKTRACE_DEPTH * 9 + 1] = {0};
    UINTPTR LR[LOSCFG_BACKTRACE_DEPTH] = {0};
    UINT32 index;

    OsBackTraceHookCall(LR, LOSCFG_BACKTRACE_DEPTH, 0, excInfo->context->sp);

    PRINTK("----- backtrace start -----\n");
    PRINTK("backtrace 0 -- lr = 0x%08" PRIxPTR "\n", excInfo->context->elr);
    for (index = 0; index < LOSCFG_BACKTRACE_DEPTH; index++) {
        if (LR[index] == 0) {
            break;
        }
        PRINTK("backtrace %u -- lr = 0x%08" PRIxPTR "\n", index + 1, LR[index]);
        sprintf_s(&buffer[index * 9], 10, " %08" PRIxPTR, LR[index]);
    }
    PRINTK("----- backtrace end -----\n");

#if defined(LOSCFG_PRODUCT) && defined(LOSCFG_BOARD)
    PRINTK("\n%saddr2line -e out/%s/%s/OHOS_Image -a -f %08" PRIxPTR "%s\n",
        LOSCFG_CROSS_COMPILE, LOSCFG_BOARD, LOSCFG_PRODUCT, excInfo->context->elr, buffer);
#else
    PRINTK("\n%saddr2line -e OHOS_Image -a -f%08" PRIxPTR "%s\n",
        LOSCFG_CROSS_COMPILE, excInfo->context->elr, buffer);
#endif
}
#endif

STATIC VOID OsExcMemPoolCheckInfo(VOID)
{
    PRINTK("\nmemory pools check:\n");
#if (LOSCFG_PLATFORM_EXC == 1)
    MemInfoCB memExcInfo[OS_SYS_MEM_NUM];

    (VOID)memset_s(memExcInfo, sizeof(memExcInfo), 0, sizeof(memExcInfo));

    UINT32 errCnt = OsMemExcInfoGet(OS_SYS_MEM_NUM, memExcInfo);
    if (errCnt < OS_SYS_MEM_NUM) {
        errCnt += OsMemboxExcInfoGet(OS_SYS_MEM_NUM - errCnt, memExcInfo + errCnt);
    }

    if (errCnt == 0) {
        PRINTK("all memory pool check passed!\n");
        return;
    }

    for (UINT32 i = 0; i < errCnt; i++) {
        PRINTK("pool num              = %u\n", i);
        PRINTK("pool type             = %u\n", memExcInfo[i].type);
        PRINTK("pool addr             = 0x%016" PRIxPTR "\n", memExcInfo[i].startAddr);
        PRINTK("pool size             = 0x%" PRIxPTR "\n", memExcInfo[i].size);
        PRINTK("pool free             = 0x%" PRIxPTR "\n", memExcInfo[i].free);
        PRINTK("pool blkNum           = %u\n", memExcInfo[i].blockSize);
        PRINTK("pool error node addr  = 0x%016" PRIxPTR "\n", memExcInfo[i].errorAddr);
        PRINTK("pool error node len   = 0x%" PRIxPTR "\n", memExcInfo[i].errorLen);
        PRINTK("pool error node owner = %d\n", memExcInfo[i].errorOwner);
    }
#endif
    UINT32 ret = LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
    if (ret == LOS_OK) {
        PRINTK("system heap memcheck over, all passed!\n");
    }

    PRINTK("memory pool check end!\n");
}
#endif

STATIC VOID OsExcInfoDisplay(const ExcInfo *excInfo)
{
#if (LOSCFG_KERNEL_PRINTF != 0)
    PRINTK("*************Exception Information**************\n");
    OsExcTypeInfo(excInfo);
    OsExcCurTaskInfo(excInfo);
    OsExcRegInfo(excInfo);
#if (LOSCFG_KERNEL_BACKTRACE == 1)
    OsExcBackTraceInfo(excInfo);
#endif
    OsGetAllTskInfo();
    OsExcMemPoolCheckInfo();
#endif
}

LITE_OS_SEC_TEXT_INIT VOID HalExcHandleEntry(UINTPTR excType, EXC_CONTEXT_S *excBufAddr, UINTPTR esr, UINTPTR far)
{
    g_intCount++;
    g_excInfo.nestCnt++;

    g_excInfo.context = excBufAddr;
    g_excInfo.type = (UINT16) ((esr >> 26) & 0x3f);
    g_excInfo.faultAddr = OS_EXC_IMPRECISE_ACCESS_ADDR;
    if (g_excInfo.type == 0x20 || g_excInfo.type == 0x21 || g_excInfo.type == 0x22 ||
        g_excInfo.type == 0x24 || g_excInfo.type == 0x25 || g_excInfo.type == 0x34 || g_excInfo.type == 0x35) {
        g_excInfo.faultAddr = far;
    }

    UINT8 mode = (UINT8) (excBufAddr->spsr & OS_EXC_MODE_MASK);
    if (mode == OS_EXC_MODE_EL1H && g_hwiCb.curHwiNum > 0) {
        g_excInfo.phase = OS_EXC_IN_HWI;
        g_excInfo.thrdPid = g_hwiCb.curHwiNum;
    } else if (LOS_TaskIsRunning()) {
        g_excInfo.phase = OS_EXC_IN_TASK;
        g_excInfo.thrdPid = g_losTask.runTask->taskID;
    } else {
        g_excInfo.phase = OS_EXC_IN_INIT;
        g_excInfo.thrdPid = OS_NULL_INT;
    }

    OsDoExcHook(EXC_INTERRUPT);
    OsExcInfoDisplay(&g_excInfo);
    ArchSysExit();
}


